/*
 Funções de criar frame de method
 Funções de inserir e retirar opcode da pilha
 */
#include "frame.h"

extern stack *framestack;
extern class_list *methodarea;
extern class_file *mainclass;

method_frame * new_frame(method_info *method, cp_info *cp, u4 method_index) {
	method_frame *new;
	int i;

	new = (method_frame*) calloc(1, sizeof(method_frame));
	for (i = 0; i < method->attributes_count; i++) {
		if (!strcmp(
				(char *) cp[method->attributes[i].attribute_name_index - 1].info.Utf8.bytes,
				"Code")) break;
	}
	if (i == method->attributes_count) {
		printf("Atributo 'Code' nao encontrado\n");
		exit(1);
	} else {
		new->pc = 0;
		new->constant_pool = cp;
		new->array = (u4*) calloc(method->attributes[i].info.Code.max_locals,
				sizeof(u4));
		new->stack = (u4*) calloc(method->attributes[i].info.Code.max_stack,
				sizeof(u4));
		new->base = new->stack;
		new->method_index = method_index;
		new->attr_code_index = i;
	}
	if (VERBOSE) printf(
			"Criado novo frame %s;\n",
			(char *) cp[method->attributes[i].attribute_name_index - 1].info.Utf8.bytes);
	return new;
}

void push_op(u4 data) {
	u4 mindex = FRAMESTACK->top->frame->method_index;
	u4 aindex = FRAMESTACK->top->frame->attr_code_index;

	if ((FRAMESTACK->top->frame->stack - FRAMESTACK->top->frame->base)
			< MAINCLASS->methods[mindex].attributes[aindex].info.Code.max_stack) {
		if (VERBOSE) printf(
				"%d) stack = %p e base = %p data inserido = %d \n",
				FRAMESTACK->top->frame->method_index,
				FRAMESTACK->top->frame->stack, FRAMESTACK->top->frame->base,
				data);
		*(FRAMESTACK->top->frame->stack) = data;
		(FRAMESTACK->top->frame->stack)++;
	} else /*Tentativa de empilhar elemento em pilha cheia*/
	{
		printf("Erro: Pilha cheia\n");
		exit(1);
	}
}

u4 pop_op(void) {
	u4 output;
	if (FRAMESTACK->top->frame->stack != FRAMESTACK->top->frame->base) {
		(FRAMESTACK->top->frame->stack)--;
		output = *(FRAMESTACK->top->frame->stack);
		if (VERBOSE) printf("%d) stack = %p e base = %p data retirado = %d \n",
				FRAMESTACK->top->frame->method_index,
				FRAMESTACK->top->frame->stack, FRAMESTACK->top->frame->base,
				output);
	} else /** Erro, tentativa de retirar elemento de pilha vazia **/
	{
		printf("Erro: Pilha vazia\n");
		exit(1);
	}

	return output;
}
